# class Hero(object):  # object 是python里所有类的最顶级父类
#     def info(self): # info是实例方法,第一个参数一般是self,表示的是实例本身
#         print("hero")
#
# class Student:
#     name = "小明"
#
#
# """
# 创建对象格式: 对象名 = 类名() => 实例化对象
# """
# hero = Hero()
# hero.info() # hero
#
#
#
#
#
# """
# 增删改查类属性
# """
# print(Student.__dict__) # 查看类的属性
# # {'__module__': '__main__', '__firstlineno__': 5,
# # 'name': '小明', '__static_attributes__': (),
# # '__dict__': <attribute '__dict__' of 'Student' objects>,
# # '__weakref__': <attribute '__weakref__' of 'Student' objects>,
# # '__doc__': None}
#
# print(Student.__dict__['name']) # 小明
#
# print(Student.name)# 小明
# Student.name = "小黄"
# print(Student.name) # 小黄
# del Student.name
# # print(Student.name) # 报错 type object 'Student' has no attribute 'name'
# Student.age = 18
# print(Student.age) # 18
#
#
# """
# 对象的属性和方法
#
# 类操作的属性,所有的对象都能访问到,但是对象操作的属性,只有对象自己访问到
# """
#
# class Dog:
#     def dark(self):
#         print("汪汪汪")
#
# dog = Dog()
#
# # 给对象添加属性
# dog.name = '小黄'
# dog.age = 17
# print(dog.name,dog.age) # 小黄 17
# dog.dark() # 汪汪汪
#
# """
# 在方法内通过self获取对象属性
# """
# class Cat:
#     def memo(self):
#         print(f"{self.name}的年龄是{self.age}")
#
# cat = Cat()
# cat.name = 'c1'
# cat.age = "4"
# print(cat.__dict__) # {'name': 'c1', 'age': '4'}
# cat.memo() #c1的年龄是4
#
# """
# 类属性和实例属性的区别
# """
# class A:
#     num = 0
#     def __init__(self,name):
#         self.name = name
#     def test(self):
#         print(f"我的名字是{self.name}")
#
# a = A('zs')
# print(a.name) # zs
# # print(A.name) # type object 'A' has no attribute 'name' 报错
# print(a.num) # 0 对象可以访问类属性
# print(A.num) # 0 类也可以访问类属性
# a.test() # 我的名字是zs
# # A.test() # A.test() missing 1 required positional argument: 'self'
# A.test(a) # 我的名字是zs



# """
# 构造函数 __init__ 方法
# """
# class Hero:
#     def __init__(self,hp,at):
#         self.name = "李白"
#         self.hp = hp
#         self.at = at
#     def move(self):
#         print(f"{self.name}正在移动")
#     def attack(self):
#         print(f"{self.name}正在以{self.at}进行攻击")
#
# h = Hero(6000,450)
# h.move() # 李白正在移动
# h.attack() # 李白正在以450进行攻击
#
# """
# 析构函数
# """
# class People:
#     def __init__(self):
#         print("调用了__init__函数")
#     def __del__(self):
#         print("调用了__del__函数")
#
# p = People()
# print("最后一句执行语句")
# # 调用了__init__函数
# # 最后一句执行语句
# # 调用了__del__函数
#
# p1 = People()
# del p1
# print("最后一句执行语句")
# # 调用了__init__函数
# # 调用了__del__函数
# # 最后一句执行语句


# """
# __str__函数 -> toString
# """
# class Dog:
#     name = "小黄"
#     age = "15"
#     love = "骨头"
#     def __str__(self):
#         return f"{self.name} 今年 {self.age} 喜欢 {self.love}"
#
# print(Dog) # <class '__main__.Dog'>
# d = Dog()
# print(d) # <class '__main__.Dog'>


# """
# 封装
# """
# class Student:
#     def __init__(self,name,age):
#         self.name = name
#         self.age = age
#
#     def info(self):
#         print(f"姓名是{self.name},年龄是{self.age}")
#
# s1 = Student("zs",19)
# s1.info() # 姓名是zs,年龄是19
# print(s1.name) #zs
# print(s1.age) #19
#
# """
# 私有属性方法 不能直接通过对象访问 但是在本类内部访问, 不能被子类继承, 子类也不能访问
# 往往用来处理类内部的事情
# 实例的变量名如果以 __ 开头,就变成了一个私有属性
# 同时一个下划线 _ 也代表私有属性和方法,实际上类对象和子类可以访问, 但是不能通过模块导入
# __xx__ 则表示用户名字空间的魔法对象
# xx_ 则是避免为了与py关键字冲突来命名的格式
#
# """
#
# """
# 私有属性
# """
# class Student:
#     def __init__(self):
#         self.__name = "哈哈哈"
#
#     def funa(self):
#         print(self.__name)
# s = Student()
# s.funa() # 哈哈哈
# # print(s.__name) # 'Student' object has no attribute '__name'
#
#
# """
# 私有方法
# """
# class Classmate:
#     def __sing(self):
#         print("唱歌")
#
#     def dance(self):
#         self.__sing()
#         print("跳舞")
# c = Classmate()
# c.dance()
# # 唱歌
# # 跳舞
# # c.__sing() # 'Classmate' object has no attribute '__sing'



# """
# 继承
#
# class 类名 (父类名):
#     pass # 什么执行语句都没有 ,可以写pass
# """
#
# class Person:
#     def sing(self):
#         print("唱歌")
#
#     def dance(self):
#         print("跳舞")
#
# class Student(Person):
#     pass
#
# s = Student()
# s.sing()
# s.dance()
# # 唱歌
# # 跳舞
#
#
# """
# 新式类与旧式类
# """
# class Person(object):
#     pass
#
# class Person():
#     pass
#
# class Person():
#     pass
#
# """
# 在py2.x中,默认都是只有显式继承,才能继承ob类
# """


# """
# 单继承
# """
# class Person:
#     s_name = "动物类"
#     def __init__(self,name,age,sex):
#         self.name = name
#         self.age = age
#         self.sex = sex
#     def eat(self):
#         print(f"{self.name} 在吃东西 性别是{self.sex} 年龄是{self.age}")
#
# class Student(Person):
#     pass
#
# s1 = Student("lucy",17,"男")
# s1.eat() # lucy 在吃东西 性别是男 年龄是17
#
# """
# 继承的传递性
# """
# class Undergraduate(Student):
#     pass
#
# u1 = Undergraduate("wcb",18,"男")
#
# u1.eat()  # wcb 在吃东西 性别是男 年龄是18



# """
# 重写
# """
# class A:
#     def test(self):
#         print("hahaha")
#
# class A1(A):
#     def test(self):
#         print("嘻嘻嘻")
#
# a = A1()
# a.test() # 嘻嘻嘻
#
# """
# 扩展父类的方法
# 1. 父类名.方法
# 2. super().方法
# """
#
# class Animal(object):
#     def eat(self):
#         print("吃东西")
#     def say(self):
#         print("说话")
# class Dog(Animal):
#     def eat(self):
#         Animal.eat(self)
#         print("啃骨头")
#
#     def say(self):
#         super().say()
#         print("汪汪汪")
#
# d = Dog()
# d.eat()
# d.say()
# # 吃东西
# # 啃骨头
# # 说话
# # 汪汪汪


# """
# 多继承
# """
# class A:
#     def test_a(self):
#         print("我是A")
#
# class B:
#     def test_b(self):
#         print("我是B")
#
#
# class C(A,B):
#     pass
#
# c = C()
# # c.test_a()
# # c.test_b()
#
# # 我是A
# # 我是B
#
# """
# 如果AB有同样的方法??
# """
# class D:
#     def test(self):
#         print("我是D")
#
# class E:
#     def test(self):
#         print("我是E")
#
#
# class F(D,E):
#     pass
#
# f = F()
# f.test()
# # 我是D
# """
# 可以通过这个方法查看类调用方法的顺序 -> 默认谁先继承就调用谁
# """
# print(F.__mro__) #(<class '__main__.F'>, <class '__main__.D'>, <class '__main__.E'>, <class 'object'>)


# """
# 类方法
# """
# class A:
#     @classmethod
#     def test(cls):
#         print(cls)
#
# A.test() #<class '__main__.A'>
#
# a = A()
# a.test() #<class '__main__.A'>
#
# """
# 静态方法
# """
# class B:
#     @staticmethod
#     def test():
#         print("我是静态方法")
#
# B.test()
#
# b = B() # 我是静态方法
# b.test() # 我是静态方法



# """
# 类型注解
# """
#
# """
# 基本类型
# """
# def fun1(a:str):
#     for ele in a:
#         print(ele)
# fun1("111")
# # fun1(111)
#
# n1: int = 10
# n2: float = 10.1
# is_pass: bool = True
#
# n1 = "1000"
#
# """
# 类类型
# """
# class Cat:
#     pass
#
# cat: Cat = Cat()
#
#
# """
# 容器类型注解
# """
# my_list: list = [100,200,300]
# my_tuple: tuple = ("run","sing")
# my_set: set = {"a","b"}
# my_dict: dict = {"name":"zs","age":100}
#
#
# """
# 容器详细类型注解
# """
#
# my_list1: list[int] = [100,200,300]
# my_tuple2: tuple[str,str,int,str] = ('1','1',2,'1')
# my_set2: set[str] = {"j","a"}
# my_dict2: dict[str,int] = {"age":111}
#
# """
# 注释中使用注解
# """
# n3 = 89.9 # type: float
#
#
# """
# 函数类型注解
# """
#
# def my_sum(a:int,b:int) -> int:
#     return a + b

#
# """
# 联合类型
# Union[X,Y] 等价于 X | Y,意味着满足 X 或 Y 之一
# """
# from typing import Union
#
# a: Union[int,str,float] = 1



# """
# 多态
# """
#
# class Food:
#     name = None
#
#     def __init__(self,name):
#         self.name = name
#
#
# class Fish(Food):
#     pass
#
# class Bone(Food):
#     pass
#
# class Animal:
#     name = None
#     def __init__(self,name):
#         self.name = name
#
#
# class Dog(Animal):
#     pass
#
# class Cat(Animal):
#     pass
#
# class Master:
#     name = None
#     def __init__(self,name):
#         self.name = name
#
#     def feed(self,animal:Animal,food:Food):
#         print(f"主人{self.name}给{animal.name}喂{food.name}")
#
#
# master = Master("wcb")
# cat = Cat("cat")
# dog = Dog("dog")
# fish = Fish("fish")
# bone = Bone("bone")
#
# master.feed(cat,fish)
# master.feed(dog,bone)
# # 主人wcb给cat喂fish
# # 主人wcb给dog喂bone


#
# """
# isinstance
# """
# class AA:
#     pass
#
# class BB(AA):
#     pass
#
# class CC:
#     pass
#
# obj = BB()
# obj2 = AA()
#
# print(f"obj 是不是 BB 的对象 {isinstance(obj,BB)}")
# print(f"obj 是不是 AA 的对象 {isinstance(obj,AA)}")
# print(f"obj 是不是 CC 的对象 {isinstance(obj,CC)}")
# """
# obj 是不是 BB 的对象 True
# obj 是不是 AA 的对象 True
# obj 是不是 CC 的对象 False
# """
#
# num = 9
# print(f"num 是不是int: {isinstance(num,int)}")
# print(f"num 是不是str: {isinstance(num,str)}")
# # num 是不是int: True
# # num 是不是str: False
#
# print(f"num 是不是str/int/list: {isinstance(num,(str,int,list))}")
# # num 是不是str/int/list: True


# """
# 魔术方法
# 在py中.所有以__包起来的方法,统称为魔术方法,他是一种特殊的方法
# 普通方法需要调用,但是魔术方法不需要调用即可自动执行
#
# """
# """
# __int__: 初始化对象的成员
# __str__: toString
# __eq__: equals
# __ne__: not equals
# """
#
# """
# __lt__ 定义小于号的行为
# """
# class Person:
#     age:int = None
#
#     def __init__(self,age):
#         self.age = age
#
#
#     def __lt__(self, other):
#         if isinstance(other,Person):
#             return self.age < other.age
#
# p = Person(12)
# p1 = Person(13)
# print(p.__lt__(p1)) # True


#
# """
# Class对象
# """
# class Monster:
#     name = "蝎子精"
#     age = 300
#
#     def hi(self):
#         print(f"hi im {self.age}")
#
# print(Monster)
#
# print(f"Monster name: {Monster.name}")
#
# Monster.hi(Monster) # hi im 300
# # <class '__main__.Monster'>
# # Monster name: 蝎子精


"""
抽象类
默认情况下,python不提供抽象类,python附带一个模块,该模块为定义抽象类提供了基础,该模块名称为abc
当我们需要抽象基类的时候,让类继承ABC, 使用@abstractmethod声明抽象方法
"""
from abc import ABC, abstractmethod


class Animal(ABC):
    @abstractmethod
    def eat(self):
        print("吃")


class Dog(Animal):
    def eat(self):
        print("狗吃")


# animal = Animal() # Can't instantiate abstract class Animal without an implementation for abstract method 'eat'
d = Dog()
d.eat() # 狗吃

